/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = tonglinkq_core.c                                              */
/*  NOTE      = TongLINK/Q协议解析                                            */
/*  DATE      = 2015/07/15 by wuwk                                            */
/******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>

#include "frservice_comm.h"
#include "tonglinkq_core.h"
#include "tonglinkq_comm.h"
#include "tonglinkq_analysis.h"
#include "config.h"

#if defined(FRLINUX4) || defined(FRLINUX5)
    #include "endian_dbg.h"
#else
    #include <endian.h>
#endif

#define TLQ_REPORT_KEY_QUEUE     APM_REPORT_KEY_SESSION ".mq.queue"
#define TLQ_REPORT_KEY_TOPIC      APM_REPORT_KEY_SESSION ".mq.topic"

extern void *g_p_apm_context;

FR_STATIC int __tonglinkq_getdata_req_analysis(L7session_tonglinkq_private *p_st_private
                                             , Conntrack *p_st_conn
                                             , Frhash_header *p_st_hash_report
                                             , Apm_packet *p_st_packet
                                             , char *p_data
                                             , unsigned int ui_data_len);

/*******************************************************************************
*  FUNC     :  释放report节点
*  ARGS     :  p_st_private(TongLINK/Q私有数据)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void __tonglinkq_report_list_free(L7session_tonglinkq_private *p_st_private)
{
    Tonglinkq_report_list *p_report_node = NULL;
    Tonglinkq_report_list *p_report_node_next = NULL;

    if (p_st_private == NULL || p_st_private->p_lst_report == NULL)
        return;

    p_report_node = p_st_private->p_lst_report;
    while (p_report_node)
    {
        p_report_node_next = p_report_node->next;
        frreport_body_free(&p_report_node->p_st_req_list);
        frfree(p_report_node);
        p_report_node = p_report_node_next;
    }

    p_st_private->p_lst_report = NULL;

    return;
}

/*******************************************************************************
*  FUNC     :  判断是否是JMS数据包
*  ARGS     :  p_st_data (数据)
*           :  i_index(数据位置)
*           :  p_u16_len(取得的数值)
*  RTN      :  FR_FAIL                   失败
*           :  FR_SUCC                   成功
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_is_jms1(Frbyte_Packet *p_st_data, int *i_flag)
{
    char arr_type[2];
    int i_ret = 0;

    if (p_st_data == NULL)
        return FR_FAIL;

    memset(arr_type, 0x00, sizeof(arr_type));
    i_ret = bytebuff_get_bytes_at(p_st_data, 3, 1, arr_type);
    if (i_ret == FR_FAIL)
        return FR_FAIL;

    if (*arr_type == '\0')
        *i_flag = TLQ_NO;
    else
        *i_flag = TLQ_YES;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  判断是否是JMS数据包
*  ARGS     :  p_st_data (数据)
*           :  i_index(数据位置)
*           :  p_u16_len(取得的数值)
*  RTN      :  FR_FAIL                   失败
*           :  FR_SUCC                   成功
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_is_jms2(char *p_data, int *i_flag)
{
    if (p_data == NULL)
        return FR_FAIL;

    if (*(p_data+3) == '\0')
        *i_flag = TLQ_NO;
    else
        *i_flag = TLQ_YES;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  取长度
*  ARGS     :  p_st_data (数据)
*           :  i_index(数据位置)
*           :  p_u16_len(取得的数值)
*  RTN      :  FR_FAIL                   失败
*           :  FR_SUCC                   成功
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_get_msglen(Frbyte_Packet *p_st_data
                                   , int i_index
                                   , uint16_t *p_u16_len)
{
    char arr_tmp[3];
    uint16_t *p_u16 = 0;
    int i_jms = TLQ_NO;
    int i_ret = 0;

    if (p_st_data == NULL || p_u16_len == NULL)
        return FR_FAIL;

    if (__tonglinkq_is_jms1(p_st_data, &i_jms) == FR_FAIL)
        return FR_FAIL;

    if (i_jms == TLQ_NO)
    {
        memset(arr_tmp, 0x00, sizeof(arr_tmp));
        i_ret = bytebuff_get_bytes_at(p_st_data, i_index, 2, arr_tmp);
        if (i_ret == FR_FAIL)
            return FR_FAIL;

        p_u16 = (uint16_t *)arr_tmp;
        *p_u16_len = be16toh(*p_u16);
    }
    else
    {
        i_ret = bytebuff_get_short(p_st_data, 2, p_u16_len, BYTE_BIG_ENDIAN);
        if (i_ret == FR_FAIL)
            return FR_FAIL;
    }

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  判断是否是内容消息
*  ARGS     :  p_st_data (数据)
*           :  i_index(数据位置)
*           :  p_u16_len(取得的数值)
*  RTN      :  FR_FAIL                   失败
*           :  FR_SUCC                   成功
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_check_msgtype(Frbyte_Packet *p_st_data, int *i_skip)
{
    char arr_tmp[2];
    int i_jms = TLQ_NO;
    int i_ret = 0;

    if (p_st_data == NULL || i_skip == NULL)
        return FR_FAIL;

    *i_skip = TLQ_NO;

    if (__tonglinkq_is_jms1(p_st_data, &i_jms) == FR_FAIL)
        return FR_FAIL;

    memset(arr_tmp, 0x00, sizeof(arr_tmp));

    if (i_jms == TLQ_NO)
    {
        i_ret = bytebuff_get_bytes_at(p_st_data, 1, 1, arr_tmp);
        if (i_ret == FR_FAIL)
            return FR_FAIL;

        if (*arr_tmp != '\x05' && *arr_tmp != '\x06')
            *i_skip = TLQ_YES;
    }

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  初始化TongLINK/Q session信息
*  ARGS     :  p_st_session (TongLINK/Q session信息)
*  RTN      :  FR_FAIL                   失败
*           :  FR_SUCC                   成功
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_init_private(L7_session *p_st_session)
{
    L7session_tonglinkq_private *p_st_private_session = NULL;
    Tonglinkq_frbyte_req *p_st_req = NULL;
    Tonglinkq_frbyte_resp *p_st_resp = NULL;
    Tonglinkq_L7session *p_st_L7_session = NULL;

    /* 申请整个私有session结构的内存 */
    p_st_private_session = (L7session_tonglinkq_private *)frmalloc(sizeof(L7session_tonglinkq_private));
    if (p_st_private_session == NULL)
        return FR_FAIL;

    memset(p_st_private_session, 0x00, sizeof(L7session_tonglinkq_private));

    /* 申请请求数据结构内存 */
    p_st_req = (Tonglinkq_frbyte_req *)frmalloc(sizeof(Tonglinkq_frbyte_req));
    if (p_st_req == NULL)
    {
        frfree(p_st_private_session);
        return FR_FAIL;
    }
    memset(p_st_req, 0x00, sizeof(Tonglinkq_frbyte_req));

    /* 申请响应数据结构内存 */
    p_st_resp = (Tonglinkq_frbyte_resp *)frmalloc(sizeof(Tonglinkq_frbyte_resp));
    if (p_st_resp == NULL)
    {
        frfree(p_st_private_session);
        frfree(p_st_req);
        return FR_FAIL;
    }
    memset(p_st_resp, 0x00, sizeof(Tonglinkq_frbyte_resp));

    /* 申请session结构内存 */
    p_st_L7_session = (Tonglinkq_L7session *)frmalloc(sizeof(Tonglinkq_L7session));
    if (p_st_L7_session == NULL)
    {
        frfree(p_st_private_session);
        frfree(p_st_req);
        frfree(p_st_resp);
        return FR_FAIL;
    }
    memset(p_st_L7_session, 0x00, sizeof(Tonglinkq_L7session));

    p_st_req->i_responserequired = 1;
    p_st_private_session->p_st_req = p_st_req;
    p_st_private_session->p_st_resp = p_st_resp;
    p_st_private_session->p_st_L7_session = p_st_L7_session;
    p_st_session->p_session_private = p_st_private_session;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  释放解析完的数据
*  ARGS     :  p_st_private(IBM MQ私有数据)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __tonglinkq_reset_analysis_data(L7session_tonglinkq_private *p_st_private)
{
    Tonglinkq_frbyte_req *p_st_req = NULL;
    Tonglinkq_frbyte_resp *p_st_resp = NULL;
    L4_transaction *p_st_l4_trans_req = NULL;
    L4_transaction *p_st_l4_trans_resp = NULL;

    if (p_st_private == NULL)
        return;

    p_st_req = p_st_private->p_st_req;
    if (p_st_req)
    {
        bytebuff_rewind(p_st_req->p_st_data_req);
        p_st_l4_trans_req = &(p_st_req->st_trans_info.st_l4_trans);
        p_st_l4_trans_req->st_request_time.tv_sec = 0;
        p_st_l4_trans_req->st_request_time.tv_usec = 0;

        p_st_req->i_pubsub_flag = TLQ_MSG_PTP;
    }

    p_st_resp = p_st_private->p_st_resp;
    if (p_st_resp)
    {
        bytebuff_rewind(p_st_resp->p_st_data_resp);
        p_st_l4_trans_resp = &(p_st_private->st_trans_info.st_l4_trans);
        p_st_l4_trans_resp->st_response_time.tv_sec = 0;
        p_st_l4_trans_resp->st_response_time.tv_usec = 0;
    }

    p_st_private->i_isnotify = TLQ_NO;

    return;
}

/*******************************************************************************
*  FUNC     :  释放解析完的数据
*  ARGS     :  p_st_private(TongLINK/Q私有数据)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __tonglinkq_reset_private(L7session_tonglinkq_private *p_st_private)
{
    Tonglinkq_frbyte_req *p_st_req = NULL;
    Tonglinkq_frbyte_resp *p_st_resp = NULL;

    if (p_st_private == NULL)
        return;

    memset(&(p_st_private->st_trans_info.st_l4_trans), 0x00, sizeof(L4_transaction));

    p_st_req = p_st_private->p_st_req;
    if (p_st_req)
    {
        if (p_st_req->p_st_data_req)
            bytebuff_free(&p_st_req->p_st_data_req);

        if (p_st_req->p_st_msg)
            bytebuff_free(&p_st_req->p_st_msg);

        frreport_body_free(&p_st_req->p_st_body_data_req);
    }

    p_st_resp = p_st_private->p_st_resp;
    if (p_st_resp)
    {
        if (p_st_resp->p_st_data_resp)
            bytebuff_free(&p_st_resp->p_st_data_resp);

        frreport_body_free(&p_st_resp->p_st_body_data_resp);
    }

    if (p_st_private->p_lst_report)
        __tonglinkq_report_list_free(p_st_private);

    return;
}

/*******************************************************************************
*  FUNC     :  释放request和response数据
*  ARGS     :  p_st_private(TongLINK/Q私有数据)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __tonglinkq_reset_round(L7session_tonglinkq_private *p_st_private)
{
    int i = 1;
    Tonglinkq_frbyte_req_list *p_st_req_node = NULL;
    Tonglinkq_frbyte_req_list *p_node = NULL;
    Tonglinkq_frbyte_resp *p_st_resp = NULL;
    Tonglinkq_frbyte_req *p_st_req = NULL;
    Tonglinkq_L7session *p_st_L7session = NULL;

    if (p_st_private == NULL)
        return;

    /* 初始化响应节点 */
    p_st_resp = p_st_private->p_st_resp;
    if (p_st_resp)
    {
        if (p_st_resp->p_st_data_resp)
            bytebuff_free(&p_st_resp->p_st_data_resp);
        frreport_body_free(&p_st_resp->p_st_body_data_resp);
        p_st_resp->i_message_ack = 0;
    }

    /* 释放session的title */
    p_st_L7session = p_st_private->p_st_L7_session;
    if (p_st_L7session)
    {
        if (p_st_L7session->p_title)
            frfree(p_st_L7session->p_title);
        p_st_L7session->p_title = NULL;
    }
    memset(&(p_st_private->st_trans_info.st_l4_trans), 0x00, sizeof(L4_transaction));
    p_st_private->i_isnotify = TLQ_NO;

     /* 找到请求节点 */
    p_st_req_node = p_st_private->p_lst_req;
    p_node = p_st_req_node;
    while (i != p_st_private->i_index && p_st_req_node != NULL)
    {
        p_node = p_st_req_node;
        p_st_req_node = p_node->next;
        i++;
    }

    if (p_st_req_node == NULL || p_st_req_node->p_st_node == NULL)
        return;

    /* 释放请求节点内存 */
    p_st_req = p_st_req_node->p_st_node;
    bytebuff_free(&p_st_req->p_st_data_req);
    frreport_body_free(&p_st_req->p_st_body_data_req);
    if (p_st_req->p_title)
        frfree(p_st_req->p_title);

    /* 释放请求节点 */
    if (p_node == p_st_req_node) /* 首节点 */
    {
        p_st_private->p_lst_req = p_st_req_node->next;
        frfree(p_st_req_node->p_st_node);
        frfree(p_st_req_node);
    }
    else if (p_st_req_node->next == NULL) /* 尾节点 */
    {
        p_node->next = NULL;
        frfree(p_st_req_node->p_st_node);
        frfree(p_st_req_node);
    }
    else /* 中间节点 */
    {
        p_node->next = p_st_req_node->next;
        frfree(p_st_req_node->p_st_node);
        frfree(p_st_req_node);
    }

    return;
}

/*******************************************************************************
*  FUNC     :  释放request数据
*  ARGS     :  p_st_private(TongLINK/Q私有数据)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void __tonglinkq_reset_request(L7session_tonglinkq_private *p_st_private)
{
    Tonglinkq_frbyte_req *p_st_req = NULL;

    if (p_st_private == NULL)
        return;

    p_st_req = p_st_private->p_st_req;
    if (p_st_req)
    {
        if (p_st_req->p_st_data_req)
            bytebuff_free(&p_st_req->p_st_data_req);
        frreport_body_free(&p_st_req->p_st_body_data_req);
        if (p_st_req->p_title)
            frfree(p_st_req->p_title);
    }

    memset(&(p_st_req->st_trans_info.st_l4_trans), 0x00, sizeof(L4_transaction));
    p_st_req->i_pubsub_flag = TLQ_MSG_PTP;

    return;
}

/*******************************************************************************
*  FUNC     :  请求数据复制到请求链表
*  ARGS     :  p_st_private(TongLINK/Q私有数据)
            :  p_st_req(请求数据)
*  RTN      :  FR_FAIL                   失败
*           :  FR_SUCC                   成功
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_add_req_list(L7session_tonglinkq_private *p_st_private
                                     , Tonglinkq_frbyte_req *p_st_req)
{
    Tonglinkq_frbyte_req_list *p_node = NULL;
    Tonglinkq_frbyte_req_list *p_node_next = NULL;
    Tonglinkq_frbyte_req *p_st_req_dest = NULL;
    Tonglinkq_L7session *p_st_L7_session = NULL;
    int i_ret = 0;

    if (p_st_private == NULL || p_st_private->p_st_L7_session == NULL || p_st_req == NULL)
        return FR_FAIL;

    p_st_L7_session = p_st_private->p_st_L7_session;

    p_node = (Tonglinkq_frbyte_req_list *)frmalloc(sizeof(Tonglinkq_frbyte_req_list));
    if (p_node == NULL)
        return FR_FAIL;
    memset(p_node, 0x00, sizeof(Tonglinkq_frbyte_req_list));

    p_st_req_dest = (Tonglinkq_frbyte_req *)frmalloc(sizeof(Tonglinkq_frbyte_req));
    if (p_st_req_dest == NULL)
    {
        frfree(p_node);
        return FR_FAIL;
    }
    memset(p_st_req_dest, 0x00, sizeof(Tonglinkq_frbyte_req));

    p_st_req_dest->ul_seq = p_st_req->ul_seq;
    p_st_req_dest->i_responserequired = p_st_req->i_responserequired;
    p_st_req_dest->p_title = frstrdup(p_st_L7_session->p_title);
    strncpy(p_st_req_dest->msgid, p_st_req->msgid, TLQ_MSGIDLEN);

    i_ret = tonglinkq_body_l7data_copy(p_st_req->p_st_body_data_req, &p_st_req_dest->p_st_body_data_req);
    if (i_ret == FR_FAIL)
    {
        frfree(p_node);
        frfree(p_st_req_dest);
        return FR_FAIL;
    }

    memcpy(&p_st_req_dest->st_trans_info.st_l4_trans, &p_st_req->st_trans_info.st_l4_trans, sizeof(L4_transaction));

    p_node->p_st_node = p_st_req_dest;
    p_node->next = NULL;

    /* 第一个 */
    if (p_st_private->p_lst_req == NULL)
    {
        p_st_private->p_lst_req = p_node;
        return FR_SUCC;
    }

    p_node_next = p_st_private->p_lst_req;
    while(p_node_next->next)
    {
        p_node_next = p_node_next->next;
    }

    p_node_next->next = p_node;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  请求数据复制到链表用做上报
*  ARGS     :  p_st_private(TongLINK/Q私有数据)
            :  p_lst_req(上报链表)
            :  i_responserequired(是否需要应答)
            :  ul_seq(序号)
            :  p_st_l4_trans(传输信息)
*  RTN      :  FR_FAIL                   失败
*           :  FR_SUCC                   成功
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_add_report_list(L7session_tonglinkq_private *p_st_private
                                        , Frreport_body_data *p_lst_req
                                        , int i_responserequired
                                        , unsigned long ul_seq
                                        , L4_transaction *p_st_l4_trans)
{
    Tonglinkq_report_list *p_node = NULL;
    Tonglinkq_report_list *p_node_next = NULL;

    if (p_st_private == NULL || p_lst_req == NULL || p_st_l4_trans == NULL)
        return FR_FAIL;

    p_node = (Tonglinkq_report_list *)frmalloc(sizeof(Tonglinkq_report_list));
    if (p_node == NULL)
        return FR_FAIL;

    memset(p_node, 0x00, sizeof(Tonglinkq_report_list));

    p_node->i_responserequired = i_responserequired;
    p_node->ul_seq = ul_seq;
    p_node->p_st_req_list = p_lst_req;
    memcpy(&(p_node->st_trans_info.st_l4_trans), p_st_l4_trans, sizeof(L4_transaction));

    /* 第一个 */
    if (p_st_private->p_lst_report == NULL)
    {
        p_st_private->p_lst_report = p_node;
        return FR_SUCC;
    }

    p_node_next = p_st_private->p_lst_report;
    while (p_node_next->next)
    {
        p_node_next = p_node_next->next;
    }

    p_node_next->next = p_node;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  TongLINK/Q session数据添加
*  ARGS     :  p_st_body_data(TongLINK/Q上报数据)
            :  p_st_l7_session(session数据)
*  RTN      :  FR_FAIL                   失败
*           :  FR_SUCC                   成功
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_add_session(Frreport_body_data *p_st_body_data
                                    , Tonglinkq_L7session *p_st_l7_session
                                    , int i_istopic)
{
    int i_ret = 0;

    if (p_st_body_data == NULL || p_st_l7_session == NULL)
        return FR_FAIL;

    /* 服务名 */
    if (p_st_l7_session->p_server != NULL)
    {
        i_ret = frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_SESSION_SERVER, p_st_l7_session->p_server);
        if (i_ret == FR_FAIL)
            return FR_FAIL;
    }

    /* 目的队列名 */
    if (p_st_l7_session->p_queue != NULL)
    {
        if (i_istopic)
            i_ret = frreport_body_l7_add_str(p_st_body_data, TLQ_REPORT_KEY_TOPIC, p_st_l7_session->p_queue);
        else
            i_ret = frreport_body_l7_add_str(p_st_body_data, TLQ_REPORT_KEY_QUEUE, p_st_l7_session->p_queue);
        if (i_ret == FR_FAIL)
            return FR_FAIL;
    }

    /* title */
    if (p_st_l7_session->p_title)
    {
        i_ret = frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_st_l7_session->p_title);
        if (i_ret == FR_FAIL)
            return FR_FAIL;
    }

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  TongLINK/Q数据上报
*  ARGS     :  p_st_private(TongLINK/Q私有数据)
            :  p_st_conn(入力链接信息)
            :  p_st_hash_report(保存Frreport_data)
            :  p_st_packet(数据)
            :  i_req_resp(请求/响应标记)
            :  i_report_flag(是否直接上报 0:上报 1:存到链表)
*  RTN      :  FR_FAIL                   失败
*           :  FR_SUCC                   成功
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_data_report(L7session_tonglinkq_private *p_st_private
                                    , Conntrack *p_st_conn
                                    , Frhash_header *p_st_hash_report
                                    , Apm_packet *p_st_packet
                                    , int i_req_resp
                                    , int i_report_flag)
{
    Frreport_body_data *p_lst_report = NULL;
    L4_transaction *p_st_l4_trans = NULL;
    L4_transaction st_l4_trans_req;
    Tonglinkq_frbyte_req *p_st_req = NULL;
    Tonglinkq_frbyte_resp *p_st_resp = NULL;
    Tonglinkq_report_list *p_report_lst = NULL;
    Frreport_body_data *p_st_body_data_req = NULL;
    Frreport_body_data *p_st_body_data = NULL;
    Frreport_data *p_st_report_data = NULL;
    Frlist_header *p_st_req_report = NULL;
    Frlist_header *p_st_mq_report = NULL;
    Tonglinkq_L7session *p_st_L7_session = NULL;
    char *p_title = NULL;
    char arr_size[64];
    unsigned long ul_seq = 0;
    unsigned long ul_time_diff = 0;
    int i_responserequired = 0;
    int i_message_ack = 0;
    int i_ret = 0;

    if (p_st_private == NULL || p_st_private->p_st_L7_session == NULL)
        return FR_FAIL;

    p_st_L7_session = p_st_private->p_st_L7_session;
    /* st_trans_info数据初始化 */
    memset(&st_l4_trans_req, 0x00, sizeof(L4_transaction));

    /*设置p_st_l4_trans */
    p_st_l4_trans = &(p_st_private->st_trans_info.st_l4_trans);

    p_st_resp = p_st_private->p_st_resp;
    if (p_st_resp != NULL && p_st_resp->i_message_ack == 2)
        i_message_ack = 1;

    /* request数据上报 */
    if (i_req_resp == TLQ_REQUEST && i_message_ack == 0)
    {
        p_st_req = p_st_private->p_st_req;
        memcpy(p_st_l4_trans,&(p_st_req->st_trans_info.st_l4_trans), sizeof(L4_transaction));

        p_st_l4_trans->st_request_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_request_time.tv_usec = p_st_packet->st_timestamp.tv_usec;
        if (frreport_body_l7_add_timeval(p_st_req->p_st_body_data_req, APM_REPORT_KEY_REQ_END_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
            goto err;

        /* 请求发送时间 */
        ul_time_diff = frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &(p_st_l4_trans->st_request_time));
        if (frreport_body_l7_add_ulong(p_st_req->p_st_body_data_req, APM_REPORT_KEY_REQ_SEND_TIME_US, ul_time_diff) == FR_FAIL)
            goto err;

        /* 请求的字节数 */
        p_st_l4_trans->l_request_bytes += p_st_req->ui_data_len;
        if (frreport_body_l7_add_long(p_st_req->p_st_body_data_req, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_l4_trans->l_request_bytes) == FR_FAIL)
            goto err;

//        memcpy(p_st_l4_trans,&(p_st_req->st_trans_info.st_l4_trans), sizeof(L4_transaction));
        memcpy(&(p_st_req->st_trans_info.st_l4_trans), p_st_l4_trans, sizeof(L4_transaction));
        i_ret = tonglinkq_body_l7data_copy(p_st_req->p_st_body_data_req
                                           , &p_st_body_data_req);
        if (i_ret == FR_FAIL)
            goto err;

        /* 添加session信息 */
        if (__tonglinkq_add_session(p_st_body_data_req, p_st_L7_session, p_st_private->i_istopic) == FR_FAIL)
            goto err;

        if (i_report_flag == 1)
        {
            i_ret = __tonglinkq_add_report_list(p_st_private, p_st_body_data_req
                                              , p_st_req->i_responserequired
                                              , p_st_req->ul_seq
                                              , p_st_l4_trans);
            if (i_ret == FR_FAIL)
                goto err;
        }
        else
        {
            if (p_st_private->p_lst_report == NULL)
            {
                if (frreport_body_l7_add_int(p_st_body_data_req, APM_REPORT_KEY_REQ_ISRESPREQUIRED, p_st_req->i_responserequired) == FR_FAIL)
                    goto err;

                /* 数据上报 */
                if (p_st_req->i_pubsub_flag == TLQ_MSG_SUB)
                    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_SUB);
                else if (p_st_req->i_pubsub_flag == TLQ_MSG_PUB)
                    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_PUB);
                else
                    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
                if (p_st_report_data == NULL)
                    goto err;

                if (frreport_data_add_body(p_st_report_data, p_st_body_data_req) == FR_FAIL)
                    goto err;

                if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
                    goto err;
                p_st_report_data = NULL;
            }
            else
            {
                i_ret = __tonglinkq_add_report_list(p_st_private, p_st_body_data_req
                                                  , p_st_req->i_responserequired
                                                  , p_st_req->ul_seq
                                                  , p_st_l4_trans);
                if (i_ret == FR_FAIL)
                    goto err;
                p_report_lst = p_st_private->p_lst_report;
                while (p_report_lst)
                {
                    p_lst_report = p_report_lst->p_st_req_list;
                    memcpy(p_st_l4_trans,&(p_report_lst->st_trans_info.st_l4_trans), sizeof(L4_transaction));

                    if (frreport_body_l7_add_int(p_st_body_data_req, APM_REPORT_KEY_REQ_ISRESPREQUIRED, p_report_lst->i_responserequired) == FR_FAIL)
                        goto err;

                    /* 数据上报 */
                    if (p_st_req->i_pubsub_flag == TLQ_MSG_SUB)
                        p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_SUB);
                    else if (p_st_req->i_pubsub_flag == TLQ_MSG_PUB)
                        p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_PUB);
                    else
                        p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
                    if (p_st_report_data == NULL)
                        goto err;

                    if (frreport_data_add_body(p_st_report_data, p_lst_report) == FR_FAIL)
                        goto err;

                    if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
                        goto err;

                    p_report_lst = p_report_lst->next;
                }
                __tonglinkq_report_list_free(p_st_private);
            }
        }

    }
    else  /* response数据上报 */
    {
        if (p_st_resp->i_message_ack == 1)
            return FR_SUCC;

//        memcpy(p_st_l4_trans, &(p_st_private->st_trans_info.st_l4_trans), sizeof(L4_transaction));
        /* 响应开始时间 */
        if (frreport_body_l7_add_timeval(p_st_resp->p_st_body_data_resp, APM_REPORT_KEY_RESP_START_TIMESTAMP, &p_st_l4_trans->st_response_time_first_byte) == FR_FAIL)
            goto err;

        /* 响应结束时间 */
        if (frreport_body_l7_add_timeval(p_st_resp->p_st_body_data_resp, APM_REPORT_KEY_RESP_END_TIMESTAMP, &p_st_l4_trans->st_response_time) == FR_FAIL)
            goto err;

        i_ret = frreport_body_l7_add_connInfo(p_st_resp->p_st_body_data_resp, p_st_conn);
        if (i_ret == FR_FAIL)
            goto err;

        /* 取对应的request数据 */
        p_st_body_data = tonglinkq_get_req_node(p_st_private, &ul_seq
                                                , &i_responserequired, &st_l4_trans_req, &p_title);
        if (p_st_L7_session->p_title == NULL && p_title != NULL)
        {
            p_st_L7_session->p_title = frstrdup(p_title);
            if (p_st_L7_session->p_title == NULL)
                goto err;
        }

        /* 添加session信息 */
        if (__tonglinkq_add_session(p_st_resp->p_st_body_data_resp, p_st_L7_session, p_st_private->i_istopic) == FR_FAIL)
            goto err;

        /* 请求数据 */
        if (p_st_body_data)
        {
            p_st_req_report = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_body_data);
            if (FRREPORT_BODY_L7LIST_SET_REQ(p_st_resp->p_st_body_data_resp, &p_st_req_report) == FR_FAIL)
                goto err;

            p_st_mq_report = FRREPORT_BODY_L7LIST_CLONE_MQ(p_st_body_data);
            frreport_body_free(&p_st_body_data);
            if (FRREPORT_BODY_L7LIST_SET_MQ(p_st_resp->p_st_body_data_resp, &p_st_mq_report) == FR_FAIL)
                goto err;

//            if (frreport_body_l7_add_str(p_st_resp->p_st_body_data_resp, APM_REPORT_KEY_TRANS_TITLE, p_title) == FR_FAIL)
//                goto err;

            if (frreport_body_l7_add_int(p_st_resp->p_st_body_data_resp, APM_REPORT_KEY_REQ_ISRESPREQUIRED, i_responserequired) == FR_FAIL)
                goto err;
        }
        else
        {
            if (p_st_private->i_istopic && p_st_L7_session->p_queue)
                i_ret = frreport_body_l7_add_str(p_st_resp->p_st_body_data_resp, MQ_NOTIFY_TOPIC, p_st_L7_session->p_queue);
            else
                i_ret = frreport_body_l7_add_str(p_st_resp->p_st_body_data_resp, MQ_NOTIFY_QUEUE, p_st_L7_session->p_queue);
            if (i_ret == FR_FAIL)
                goto err;

            snprintf(arr_size, sizeof(arr_size), "notify.%s", MQ_MESSAGE_SIZE);
            // 消息个数上报
            i_ret = frreport_body_l7_add_int(p_st_resp->p_st_body_data_resp, arr_size, p_st_resp->i_msg_size);
            if (i_ret == FR_FAIL)
                goto err;
            p_st_private->i_isnotify = TLQ_YES;
        }

        p_st_l4_trans->st_request_time_first_byte.tv_sec = st_l4_trans_req.st_request_time_first_byte.tv_sec;
        p_st_l4_trans->st_request_time_first_byte.tv_usec = st_l4_trans_req.st_request_time_first_byte.tv_usec;
        p_st_l4_trans->st_request_time.tv_sec = st_l4_trans_req.st_request_time.tv_sec;
        p_st_l4_trans->st_request_time.tv_usec = st_l4_trans_req.st_request_time.tv_usec;
        p_st_l4_trans->l_request_bytes = st_l4_trans_req.l_request_bytes;
        if (st_l4_trans_req.st_request_time_first_byte.tv_sec != 0)
        {
            /* 服务器运行时间 */
            ul_time_diff = frtime_diff(&(p_st_l4_trans->st_request_time), &(p_st_private->st_trans_info.st_l4_trans.st_response_time_first_byte));
            if (frreport_body_l7_add_ulong(p_st_resp->p_st_body_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, ul_time_diff) == FR_FAIL)
                goto err;
        }
        else
        {
            if (frreport_body_l7_add_ulong(p_st_resp->p_st_body_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, 0) == FR_FAIL)
                goto err;
        }

        /* 下载时间 */
        p_st_l4_trans->ul_response_time_us = frtime_diff(&(p_st_l4_trans->st_response_time_first_byte), &(p_st_private->st_trans_info.st_l4_trans.st_response_time));
        if (frreport_body_l7_add_ulong(p_st_resp->p_st_body_data_resp, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, p_st_l4_trans->ul_response_time_us) == FR_FAIL)
            goto err;

        /* 响应的字节数 */
        if (frreport_body_l7_add_long(p_st_resp->p_st_body_data_resp, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_l4_trans->l_response_bytes) == FR_FAIL)
            goto err;

        /* 数据上报 */
        if (p_st_private->i_isnotify == TLQ_YES)
            p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_NOTIFY);
        else
            p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
        if (p_st_report_data == NULL)
            goto err;

        if (frreport_data_add_body(p_st_report_data, p_st_resp->p_st_body_data_resp) == FR_FAIL)
            goto err;
        p_st_resp->p_st_body_data_resp = NULL;

        if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
            goto err;
        p_st_report_data = NULL;

        if (i_ret == FR_FAIL)
            goto err;
    }
    return FR_SUCC;

err:
    if (p_lst_report)
        frreport_body_free(&p_lst_report);

    if (p_st_body_data_req)
        frreport_body_free(&p_st_body_data_req);

    if (p_st_body_data)
        frreport_body_free(&p_st_body_data);

    if (p_st_req_report)
        frreport_body_l7list_free(&p_st_req_report);

    if (p_st_mq_report)
        frreport_body_l7list_free(&p_st_mq_report);

    if (p_st_report_data)
        frreport_data_hash(p_st_hash_report, p_st_report_data);

    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  TongLINK/Q的请求解析
*  ARGS     :  p_st_private(TongLINK/Q私有数据)
            :  p_st_conn(入力链接信息)
            :  p_st_hash_report(保存Frreport_data)
            :  p_st_packet(入力packet信息)
            :  i_report_flag(是否直接上报 0:上报 1:存到链表)
*  RTN      :  int
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_req_analysis(L7session_tonglinkq_private *p_st_private
                                     , Conntrack *p_st_conn
                                     , Frhash_header *p_st_hash_report
                                     , Apm_packet *p_st_packet
                                     , int i_report_flag)
{
    int i_ret = 0;
    int i_need_report = TLQ_YES;
//    unsigned long ul_time_diff = 0;
    L4_transaction *p_st_l4_trans = NULL;
    Tonglinkq_frbyte_req *p_st_req = NULL;

    if (p_st_private == NULL || p_st_private->p_st_req == NULL
        || p_st_conn == NULL || p_st_hash_report == NULL || p_st_packet == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_req = p_st_private->p_st_req;
    p_st_l4_trans = &(p_st_req->st_trans_info.st_l4_trans);

    if (p_st_req->p_st_body_data_req == NULL)
    {
        p_st_req->p_st_body_data_req = frreport_body_new_l7(p_st_conn);
        if (p_st_req->p_st_body_data_req == NULL)
            return APM_L7_ANALYZE_FAIL;
    }

    /* 不是上次剩余的数据包 */
    if (p_st_req->p_st_msg == NULL)
    {
        if (p_st_l4_trans->st_request_time_first_byte.tv_sec == 0
            && p_st_l4_trans->st_request_time_first_byte.tv_usec == 0)
        {
            /* 请求发起的第一个数据包时间 */
            p_st_l4_trans->st_request_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
            p_st_l4_trans->st_request_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

            p_st_req->ul_seq = frct_seq_increase(p_st_conn);
        }

        if (frreport_body_l7_add_connInfo(p_st_req->p_st_body_data_req, p_st_conn) == FR_FAIL)
            goto err;

        if (frreport_body_l7_add_ulong(p_st_req->p_st_body_data_req, APM_REPORT_KEY_REQ_ID, p_st_req->ul_seq) == FR_FAIL)
            goto err;

        if (frreport_body_l7_add_timeval(p_st_req->p_st_body_data_req, APM_REPORT_KEY_REQ_START_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
            goto err;
    }

    /* TongLINK/Q数据解析 */
    i_ret = tonglinkq_analysis_data(p_st_private, p_st_req->p_st_body_data_req, TLQ_REQUEST, &i_need_report);
    if (i_ret == FR_SUCC)
    {
        if (p_st_req->p_st_msg != NULL || i_need_report == TLQ_NO)
        {
            if (i_need_report == TLQ_NO)
            {
                //frreport_body_free(&p_st_req->p_st_body_data_req);
                __tonglinkq_reset_request(p_st_private);
            }
            return i_ret;
        }
        /* 数据上报 */
        i_ret = __tonglinkq_data_report(p_st_private, p_st_conn, p_st_hash_report
                                      , p_st_packet, TLQ_REQUEST, i_report_flag);
        if (i_ret == APM_L7_ANALYZE_TODO)
            return i_ret;
        else if (i_ret == FR_FAIL)
            return APM_L7_ANALYZE_FAIL;

        i_ret = __tonglinkq_add_req_list(p_st_private, p_st_req);
        if (i_ret == FR_FAIL)
            return APM_L7_ANALYZE_FAIL;

        __tonglinkq_reset_request(p_st_private);

        return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
    }
    else if (i_ret == APM_L7_ANALYZE_TODO)
    {
        if (p_st_req->p_st_msg == NULL)
        {
            if (p_st_req->p_st_body_data_req)
                frreport_body_free(&p_st_req->p_st_body_data_req);
        }

        return i_ret;
    }

    return i_ret;

err:
    if (p_st_req->p_st_body_data_req)
        frreport_body_free(&p_st_req->p_st_body_data_req);

    return APM_L7_ANALYZE_FAIL;
}

/*******************************************************************************
*  FUNC     :  TongLINK/Q的响应解析
*  ARGS     :  p_st_private(TongLINK/Q私有数据)
            :  p_st_conn(入力链接信息)
            :  p_st_hash_report(保存Frreport_data)
            :  p_st_packet(入力packet信息)
*  RTN      :  int
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_resp_analysis(L7session_tonglinkq_private *p_st_private
                                      , Conntrack *p_st_conn
                                      , Frhash_header *p_st_hash_report
                                      , Apm_packet *p_st_packet)
{
    int i_ret = 0;
    int i_need_report = TLQ_YES;
    L4_transaction *p_st_l4_trans = NULL;
    Tonglinkq_frbyte_resp *p_st_resp = NULL;

    if (p_st_private == NULL || p_st_private->p_st_resp == NULL
        || p_st_conn == NULL || p_st_hash_report == NULL || p_st_packet == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_resp = p_st_private->p_st_resp;
    p_st_l4_trans = &(p_st_private->st_trans_info.st_l4_trans);

    if (p_st_resp->p_st_body_data_resp == NULL)
    {
        p_st_resp->p_st_body_data_resp = frreport_body_new_l7(p_st_conn);
        if (p_st_resp->p_st_body_data_resp == NULL)
            return APM_L7_ANALYZE_FAIL;
    }

    if (p_st_l4_trans->st_response_time_first_byte.tv_sec == 0
        && p_st_l4_trans->st_response_time_first_byte.tv_usec == 0)
    {
        /* 响应发起的第一个数据包时间 */
        p_st_l4_trans->st_response_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_response_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;
    }

    /* 结束时间 */
    p_st_l4_trans->st_response_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_response_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

    /* 响应的字节数 */
    p_st_l4_trans->l_response_bytes += p_st_packet->ui_payload_len;

    /* TongLINK/Q体部数据解析 */
    i_ret = tonglinkq_analysis_data(p_st_private, p_st_resp->p_st_body_data_resp, TLQ_RESPONSE, &i_need_report);
    if (i_ret == FR_SUCC)
    {
        if (i_need_report == TLQ_NO)
        {
            frreport_body_free(&p_st_resp->p_st_body_data_resp);
            memset(&(p_st_private->st_trans_info.st_l4_trans), 0x00, sizeof(L4_transaction));
            return i_ret;
        }

        /* 数据上报 */
        i_ret = __tonglinkq_data_report(p_st_private, p_st_conn, p_st_hash_report
                                      , p_st_packet, TLQ_RESPONSE, 0);
        if (i_ret == FR_FAIL)
            goto err;

        /* 没收到message ack包,不清空 */
        if (p_st_resp->i_message_ack != 1)
            __tonglinkq_reset_round(p_st_private);

        return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
    }
    else if (i_ret == APM_L7_ANALYZE_TODO)
    {
        if (p_st_resp->p_st_body_data_resp)
            frreport_body_free(&p_st_resp->p_st_body_data_resp);

        return i_ret;
    }

    return i_ret;

err:
    if (p_st_resp->p_st_body_data_resp)
        frreport_body_free(&p_st_resp->p_st_body_data_resp);

    return APM_L7_ANALYZE_FAIL;
}

/*******************************************************************************
*  FUNC     :  取得完整的请求数据包并解析
*  ARGS     :  p_st_private(TongLINK/Q私有数据)
            :  p_st_conn(入力链接信息)
            :  p_st_hash_report(保存Frreport_data)
            :  p_st_packet(入力packet信息)
            :  p_data(入力数据)
            :  ui_data_len(数据长度)
*  RTN      :  int
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_getdata_req_analysis(L7session_tonglinkq_private *p_st_private
                                             , Conntrack *p_st_conn
                                             , Frhash_header *p_st_hash_report
                                             , Apm_packet *p_st_packet
                                             , char *p_data
                                             , unsigned int ui_data_len)
{
    Tonglinkq_frbyte_req *p_st_req = NULL;
    char arr_len[3];
    uint16_t *p_u16_len = NULL;
    uint16_t u16_len = 0;
    int i_report_flag = 0;
    int i_skip = TLQ_NO;
    int i_jms = TLQ_NO;
    int i_ret = 0;

    if (p_st_private == NULL || p_st_conn == NULL || p_st_hash_report == NULL
        || p_st_packet == NULL || p_data == NULL)
        return APM_L7_ANALYZE_FAIL;

    if (ui_data_len == 0)
        return APM_L7_ANALYZE_TODO;

    p_st_req = p_st_private->p_st_req;
    if (p_st_req->p_st_data_req == NULL)
    {
        /* 做成请求bytebuffer */
        p_st_req->p_st_data_req = bytebuff_creat();
        if (p_st_req->p_st_data_req == NULL)
            goto err;
    }

    /* 上次的数据包不完整 */
    if (p_st_req->ui_recv_len)
    {
        /* 前次数据长度小于10, 没有取到数据长度 */
        if (p_st_req->ui_data_len == 0)
        {
            /* 前次数据+本次数据的长度小于10 */
            if (p_st_req->ui_recv_len + ui_data_len < 10)
            {
                p_st_req->ui_recv_len += ui_data_len;
                i_ret = bytebuff_add(p_st_req->p_st_data_req, p_data, ui_data_len);
                if (i_ret != FR_SUCC)
                    goto err;
                return APM_L7_ANALYZE_TODO;
            }
            else
            {
                i_ret = __tonglinkq_get_msglen(p_st_req->p_st_data_req, 8, &u16_len);
                if (i_ret != FR_SUCC)
                    goto err;
                p_st_req->ui_data_len = u16_len;
            }
        }
        /* 还需要接收的数据长度大于本次数据的长度，即本次数据不够完成本次解析 */
        if (p_st_req->ui_left_len > ui_data_len)
        {
            /* 将本次数据存入buffer */
            i_ret = bytebuff_add(p_st_req->p_st_data_req, p_data, ui_data_len);
            if (i_ret != FR_SUCC)
                goto err;
            p_st_req->ui_left_len -= ui_data_len;
            return APM_L7_ANALYZE_TODO;
        }

        /* 获取本次解析还需要的数据 */
        i_ret = bytebuff_add(p_st_req->p_st_data_req, p_data, p_st_req->ui_left_len);
        if (i_ret != FR_SUCC)
            goto err;

        p_data += p_st_req->ui_left_len;
        ui_data_len -= p_st_req->ui_left_len;
        p_st_req->ui_left_len = 0;
        p_st_req->ui_recv_len = 0;

        if (ui_data_len > 0 && *p_data != '\0')
            i_report_flag = 1;

        /* 判断是否是数据内容的数据包，如果不是，则跳过 */
        i_ret = __tonglinkq_check_msgtype(p_st_req->p_st_data_req, &i_skip);
        if (i_ret != FR_SUCC)
            goto err;

        if (i_skip == TLQ_YES)
        {
            bytebuff_free(&p_st_req->p_st_data_req);
            /* 还需要接收数据长度的初始化 */
            p_st_req->ui_left_len = 0;
            p_st_req->ui_recv_len = 0;
            return APM_L7_ANALYZE_SUCC;
        }

        /* 解析当前数据 */
        i_ret = __tonglinkq_req_analysis(p_st_private, p_st_conn, p_st_hash_report, p_st_packet, i_report_flag);
        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto err;
        else if (i_ret == APM_L7_ANALYZE_TODO)
        {
            if (p_st_req->p_st_msg != NULL)
            {
                bytebuff_free(&p_st_req->p_st_data_req);
                p_st_req->ui_left_len = 0;
                p_st_req->ui_recv_len = 0;
            }
        }
        else
        {
            bytebuff_free(&p_st_req->p_st_data_req);
            /* 还需要接收数据长度的初始化 */
            p_st_req->ui_left_len = 0;
            p_st_req->ui_recv_len = 0;
        }

        if (ui_data_len > 0)
        {
            i_ret = __tonglinkq_getdata_req_analysis(p_st_private, p_st_conn, p_st_hash_report
                                                   , p_st_packet, p_data, ui_data_len);
            if (i_ret == APM_L7_ANALYZE_FAIL)
                goto err;
        }
        return i_ret;
    }

    /* TONG_JMS的前两位是数据包长度，第一位可能是\0 */
    if (*p_data == '\0')
    {
        if (ui_data_len == 1 || *(p_data + 1) == '\0')
        {
            bytebuff_free(&p_st_req->p_st_data_req);
            /* 还需要接收数据长度的初始化 */
            p_st_req->ui_left_len = 0;
            p_st_req->ui_recv_len = 0;
            return APM_L7_ANALYZE_SUCC;
        }
    }

    /* 上次的数据包完整，开始新的数据包解析 */
    if (ui_data_len >= 10)
    {
        if (__tonglinkq_is_jms2(p_data, &i_jms) == FR_FAIL)
            goto err;

        memset(arr_len, 0x00, sizeof(arr_len));
        if (i_jms == TLQ_NO)
            memcpy(arr_len, p_data + 8, 2);
        else
            memcpy(arr_len, p_data, 2);
        p_u16_len = (uint16_t *)arr_len;
        p_st_req->ui_data_len = ntohs(*p_u16_len);
    }
    else
    {
        i_ret = bytebuff_add(p_st_req->p_st_data_req, p_data, ui_data_len);
        if (i_ret != FR_SUCC)
            goto err;
        p_st_req->ui_recv_len = ui_data_len;
        return APM_L7_ANALYZE_TODO;
    }

    /* 数据长度不够 */
    if (p_st_req->ui_data_len > ui_data_len)
    {
        i_ret = bytebuff_add(p_st_req->p_st_data_req, p_data, ui_data_len);
        if (i_ret != FR_SUCC)
            goto err;
        p_st_req->ui_left_len = p_st_req->ui_data_len - ui_data_len;
        p_st_req->ui_recv_len = ui_data_len;
        return APM_L7_ANALYZE_TODO;
    }

    i_ret = bytebuff_add(p_st_req->p_st_data_req, p_data, p_st_req->ui_data_len);
    if (i_ret != FR_SUCC)
        goto err;

    p_data += p_st_req->ui_data_len;
    ui_data_len -= p_st_req->ui_data_len;
    if (ui_data_len > 0 && *p_data != '\0')
        i_report_flag = 1;

    /* 判断是否是数据内容的数据包，如果不是，则跳过 */
    i_ret = __tonglinkq_check_msgtype(p_st_req->p_st_data_req, &i_skip);
    if (i_ret != FR_SUCC)
        goto err;

    if (i_skip == TLQ_YES)
    {
        bytebuff_free(&p_st_req->p_st_data_req);
        /* 还需要接收数据长度的初始化 */
        p_st_req->ui_left_len = 0;
        p_st_req->ui_recv_len = 0;
        return APM_L7_ANALYZE_SUCC;
    }

    /* 解析数据 */
    i_ret = __tonglinkq_req_analysis(p_st_private, p_st_conn, p_st_hash_report, p_st_packet, i_report_flag);
    if (i_ret == APM_L7_ANALYZE_FAIL)
        goto err;
    else if (i_ret == APM_L7_ANALYZE_TODO)
    {
        if (p_st_req->p_st_msg != NULL)
        {
            bytebuff_free(&p_st_req->p_st_data_req);
            p_st_req->ui_left_len = 0;
            p_st_req->ui_recv_len = 0;
        }
    }
    else
    {
        bytebuff_free(&p_st_req->p_st_data_req);
        /* 还需要接收数据长度的初始化 */
        p_st_req->ui_left_len = 0;
        p_st_req->ui_recv_len = 0;
    }

    if (ui_data_len > 0)
    {
        i_ret = __tonglinkq_getdata_req_analysis(p_st_private, p_st_conn, p_st_hash_report
                                               , p_st_packet, p_data, ui_data_len);
        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto err;
    }
    return i_ret;

err:
    __tonglinkq_reset_private(p_st_private);
    return APM_L7_ANALYZE_FAIL;
}

/*******************************************************************************
*  FUNC     :  取得完整的响应数据包并解析
*  ARGS     :  p_st_private(TongLINK/Q私有数据)
            :  p_st_conn(入力链接信息)
            :  p_st_hash_report(保存Frreport_data)
            :  p_st_packet(入力packet信息)
            :  p_data(入力数据)
            :  ui_data_len(数据长度)
*  RTN      :  int
*  NOTE     :
*******************************************************************************/
FR_STATIC int __tonglinkq_getdata_resp_analysis(L7session_tonglinkq_private *p_st_private
                                              , Conntrack *p_st_conn
                                              , Frhash_header *p_st_hash_report
                                              , Apm_packet *p_st_packet
                                              , char *p_data
                                              , unsigned int ui_data_len)
{
    Tonglinkq_frbyte_resp *p_st_resp = NULL;
    char arr_len[3];
    char arr_tmp[11];
    uint16_t *p_u16_len = NULL;
    uint16_t u16_len = 0;
    int i_skip = TLQ_NO;
    int i_jms = TLQ_NO;
    int i_ret = 0;

    if (p_st_private == NULL || p_st_conn == NULL || p_st_hash_report == NULL
        || p_st_packet == NULL || p_data == NULL)
        return APM_L7_ANALYZE_FAIL;

    if (ui_data_len == 0)
        return APM_L7_ANALYZE_TODO;

    p_st_resp = p_st_private->p_st_resp;
    if (p_st_resp->p_st_data_resp == NULL)
    {
        /* 做成请求bytebuffer */
        p_st_resp->p_st_data_resp = bytebuff_creat();
        if (p_st_resp->p_st_data_resp == NULL)
            goto err;
    }

    /* 上次的数据包不完整 */
    if (p_st_resp->ui_recv_len)
    {
        /* 前次数据长度小于10, 没有取到数据长度 */
        if (p_st_resp->ui_data_len == 0)
        {
            /* 前次数据+本次数据的长度小于10 */
            if (p_st_resp->ui_recv_len + ui_data_len < 10)
            {
                p_st_resp->ui_recv_len += ui_data_len;
                i_ret = bytebuff_add(p_st_resp->p_st_data_resp, p_data, ui_data_len);
                if (i_ret != FR_SUCC)
                    goto err;
                return APM_L7_ANALYZE_TODO;
            }
            else
            {
                i_ret = __tonglinkq_get_msglen(p_st_resp->p_st_data_resp, 8, &u16_len);
                if (i_ret != FR_SUCC)
                    goto err;
                p_st_resp->ui_data_len = u16_len;
            }
        }
        /* 还需要接收的数据长度大于本次数据的长度，即本次数据不够完成本次解析 */
        if (p_st_resp->ui_left_len > ui_data_len)
        {
            /* 将本次数据存入buffer */
            i_ret = bytebuff_add(p_st_resp->p_st_data_resp, p_data, ui_data_len);
            if (i_ret != FR_SUCC)
                goto err;
            p_st_resp->ui_left_len -= ui_data_len;
            return APM_L7_ANALYZE_TODO;
        }

        /* 获取本次解析还需要的数据 */
//        i_ret = bytebuff_add(p_st_resp->p_st_data_resp, p_data, p_st_resp->ui_left_len);
        i_ret = bytebuff_add(p_st_resp->p_st_data_resp, p_data, ui_data_len);
        if (i_ret != FR_SUCC)
            goto err;

        /* 判断是否是数据内容的数据包，如果不是，则跳过 */
        i_ret = __tonglinkq_check_msgtype(p_st_resp->p_st_data_resp, &i_skip);
        if (i_ret != FR_SUCC)
            goto err;

        if (i_skip == TLQ_YES)
        {
            bytebuff_free(&p_st_resp->p_st_data_resp);
            /* 还需要接收数据长度的初始化 */
            p_st_resp->ui_left_len = 0;
            p_st_resp->ui_recv_len = 0;
            return APM_L7_ANALYZE_SUCC;
        }

        /* 解析当前数据 */
        i_ret = __tonglinkq_resp_analysis(p_st_private, p_st_conn, p_st_hash_report, p_st_packet);
        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto err;
        else if (i_ret == APM_L7_ANALYZE_TODO)
        {
            __tonglinkq_reset_analysis_data(p_st_private);
            p_st_resp->ui_left_len = 0;
            p_st_resp->ui_recv_len = 0;

            return APM_L7_ANALYZE_TODO;
        }
        else
        {
            bytebuff_free(&p_st_resp->p_st_data_resp);
            /* 还需要接收数据长度的初始化 */
            p_st_resp->ui_left_len = 0;
            p_st_resp->ui_recv_len = 0;
            return APM_L7_ANALYZE_SUCC;
        }
    }

    /* TONG_JMS的前两位是数据包长度，第一位可能是\0 */
    if (*p_data == '\0')
    {
        if (ui_data_len == 1 || *(p_data + 1) == '\0')
        {
            bytebuff_free(&p_st_resp->p_st_data_resp);
            /* 还需要接收数据长度的初始化 */
            p_st_resp->ui_left_len = 0;
            p_st_resp->ui_recv_len = 0;
            return APM_L7_ANALYZE_SUCC;
        }
    }

    /* 上次的数据包完整，开始新的数据包解析 */
    if (ui_data_len != 0)
    {
        i_ret = bytebuff_add(p_st_resp->p_st_data_resp, p_data, ui_data_len);
        if (i_ret != FR_SUCC)
            goto err;
    }

    if (ui_data_len > 10)
    {
        memset(arr_tmp, 0x00, sizeof(arr_tmp));
        if (bytebuff_peek_bytes(p_st_resp->p_st_data_resp, arr_tmp, 10) == FR_FAIL)
            goto err;
        if (__tonglinkq_is_jms2(arr_tmp, &i_jms) == FR_FAIL)
            goto err;

        memset(arr_len, 0x00, sizeof(arr_len));
        if (i_jms == TLQ_NO)
            memcpy(arr_len, arr_tmp + 8, 2);
        else
            memcpy(arr_len, arr_tmp, 2);
        p_u16_len = (uint16_t *)arr_len;
        p_st_resp->ui_data_len = ntohs(*p_u16_len);
    }
    else
    {
        p_st_resp->ui_recv_len = ui_data_len;
        return APM_L7_ANALYZE_TODO;
    }

    /* 数据长度不够 */
    if (p_st_resp->ui_data_len > ui_data_len)
    {
        p_st_resp->ui_left_len = p_st_resp->ui_data_len - ui_data_len;
        p_st_resp->ui_recv_len = ui_data_len;
        return APM_L7_ANALYZE_TODO;
    }

    /* 判断是否是数据内容的数据包，如果不是，则跳过 */
    i_ret = __tonglinkq_check_msgtype(p_st_resp->p_st_data_resp, &i_skip);
    if (i_ret != FR_SUCC)
        goto err;

    if (i_skip == TLQ_YES)
    {
        bytebuff_free(&p_st_resp->p_st_data_resp);
        /* 还需要接收数据长度的初始化 */
        p_st_resp->ui_left_len = 0;
        p_st_resp->ui_recv_len = 0;
        return APM_L7_ANALYZE_SUCC;
    }

    /* 解析数据 */
    i_ret = __tonglinkq_resp_analysis(p_st_private, p_st_conn, p_st_hash_report, p_st_packet);
    if (i_ret == APM_L7_ANALYZE_FAIL)
        goto err;
    else if (i_ret == APM_L7_ANALYZE_TODO)
    {
        p_st_resp->ui_recv_len = ui_data_len;
        __tonglinkq_reset_analysis_data(p_st_private);

        return APM_L7_ANALYZE_TODO;
    }
    else
    {
        bytebuff_free(&p_st_resp->p_st_data_resp);
        /* 还需要接收数据长度的初始化 */
        p_st_resp->ui_left_len = 0;
        p_st_resp->ui_recv_len = 0;
        return APM_L7_ANALYZE_SUCC;
    }

err:
    __tonglinkq_reset_private(p_st_private);
    return APM_L7_ANALYZE_FAIL;
}

/*******************************************************************************
*  FUNC     :  请求链表销毁
*  ARGS     :  p_lst_req(请求链表)
*  RTN      :  int
*  NOTE     :
*******************************************************************************/
void __tonglinkq_destroy_list(Tonglinkq_frbyte_req_list *p_lst_req)
{
    Tonglinkq_frbyte_req_list *p_lst_next = NULL;
    Tonglinkq_frbyte_req *p_st_req = NULL;

    if (p_lst_req == NULL)
        return;

    while (p_lst_req)
    {
        p_lst_next = p_lst_req->next;

        p_st_req = p_lst_req->p_st_node;
        /* 释放请求节点内存 */
        bytebuff_free(&p_st_req->p_st_data_req);
        frreport_body_free(&p_st_req->p_st_body_data_req);
        frfree(p_st_req->p_title);

        /* 释放请求节点 */
        frfree(p_lst_req->p_st_node);
        frfree(p_lst_req);
        p_lst_req = p_lst_next;
    }

    return;
}

/*******************************************************************************
*  FUNC     :  私有信息销毁
*  ARGS     :  p_private_session(TongLINK/Q的私有session数据)
*  RTN      :  int
*  NOTE     :
*******************************************************************************/
int tonglinkq_session_destroy(void *p_private_session)
{
    L7session_tonglinkq_private *p_st_private = NULL;
    Tonglinkq_frbyte_req *p_st_req = NULL;
    Tonglinkq_frbyte_resp *p_st_resp = NULL;
    Tonglinkq_frbyte_req_list *p_lst_req = NULL;
    Tonglinkq_L7session *p_st_L7_session = NULL;

    /* 判断session是否为空 */
    if (p_private_session == NULL)
        return FR_SUCC;

    p_st_private = (L7session_tonglinkq_private *)p_private_session;

    p_st_req = p_st_private->p_st_req;
    p_st_resp = p_st_private->p_st_resp;
    p_lst_req = p_st_private->p_lst_req;

    if (p_st_req)
    {
        if (p_st_req->p_st_data_req)
            bytebuff_free(&p_st_req->p_st_data_req);
        frreport_body_free(&p_st_req->p_st_body_data_req);
        if (p_st_req->p_title)
            frfree(p_st_req->p_title);
    }
    if (p_st_resp)
    {
        if (p_st_resp->p_st_data_resp)
            bytebuff_free(&p_st_resp->p_st_data_resp);
        frreport_body_free(&p_st_resp->p_st_body_data_resp);
    }
    if (p_lst_req)
        __tonglinkq_destroy_list(p_lst_req);
    if (p_st_private->p_lst_report)
        __tonglinkq_report_list_free(p_st_private);

    if (p_st_private->p_st_L7_session)
    {
        p_st_L7_session = p_st_private->p_st_L7_session;

        if (p_st_L7_session->p_server)
            frfree(p_st_L7_session->p_server);
        if (p_st_L7_session->p_queue)
            frfree(p_st_L7_session->p_queue);
        if (p_st_L7_session->p_title)
            frfree(p_st_L7_session->p_title);

        frfree(p_st_L7_session);
    }

    frfree(p_st_req);
    frfree(p_st_resp);
    frfree(p_st_private);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  判断当前数据链路是否是tonglinkq协议
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_packet(入力数据包)
*  RTN      :  APM_L7_IS_NO   (NO)
*              APM_L7_IS_YES  (YES)
*  NOTE     :
*******************************************************************************/
int tonglinkq_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    char *p_payload = NULL;
    unsigned char *p_payload_tmp = NULL;
    char arr_destname[16];
    char arr_len[3];
    unsigned int ui_len = 0;
    unsigned int ui_offset = 0;
    unsigned int ui_seg_len = 0;
    uint16_t *p_u16_len = NULL;
    int i_ret = 0;

    if (p_st_conn == NULL || p_st_packet == NULL || p_st_packet->p_payload == NULL)
        return APM_L7_IS_NO;

    p_payload = p_st_packet->p_payload;
    p_payload_tmp = (unsigned char *)p_payload;
    ui_len = p_st_packet->ui_payload_len;

    memset(arr_len, 0x00, sizeof(arr_len));
    if (*p_payload_tmp == '\x08' && ui_len > 10)
    {
        /* 方向明确 */
        if (frct_get_direct_known(p_st_conn) == FR_DIRECT_KNOWN)
        {
            /* 请求 */
            if (p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
            {
                /* 服务器IP */
                if (ui_len < 172)
                    goto end;

                memset(arr_destname, 0x00, sizeof(arr_destname));
                strncpy(arr_destname, (char *)p_payload_tmp+157, 15);
            }
            else
            {
                /* 服务器IP */
                if (ui_len < 25)
                    goto end;

                memset(arr_destname, 0x00, sizeof(arr_destname));
                strncpy(arr_destname, (char *)p_payload_tmp+10, 15);
            }

            if (strncmp(arr_destname, int_ntoa(p_st_packet->dst_ip), strlen(int_ntoa(p_st_packet->dst_ip))) == 0)
            {
                frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
                return APM_L7_IS_YES;
            }
            else
                goto end;
        }

        /* 59为队列控制单元名的offset */
        ui_offset = 59 + (TLQ_NAMELEN + 1)*2;
        if (ui_len < ui_offset)
            goto end;

        /* 没有队列控制单元名 */
        if (*(p_payload_tmp+59) == '\0')
        {
            memset(arr_destname, 0x00, sizeof(arr_destname));
            strncpy(arr_destname, (char *)p_payload_tmp+10, 15);
            if (strncmp(arr_destname, int_ntoa(p_st_packet->dst_ip), strlen(int_ntoa(p_st_packet->dst_ip))) != 0)
            {
                if (strncmp(arr_destname, int_ntoa(p_st_packet->src_ip), strlen(int_ntoa(p_st_packet->src_ip))) == 0)
                {
                    i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
                    if (i_ret != FR_SUCC)
                    {
                        frdbg("frcap_set_cs_srv failed\n");
                        return APM_L7_IS_NO;
                    }
                }
                else
                    goto end;
            }
            else
                goto succ;
        }
        else
        {
            if (ui_len < 172)
                goto end;

            memset(arr_destname, 0x00, sizeof(arr_destname));
            strncpy(arr_destname, (char *)p_payload_tmp+157, 15);
            if (strncmp(arr_destname, int_ntoa(p_st_packet->dst_ip), strlen(int_ntoa(p_st_packet->dst_ip))) != 0)
            {
                if (strncmp(arr_destname, int_ntoa(p_st_packet->src_ip), strlen(int_ntoa(p_st_packet->src_ip))) == 0)
                {
                    i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
                    if (i_ret != FR_SUCC)
                    {
                        frdbg("frcap_set_cs_srv failed\n");
                        return APM_L7_IS_NO;
                    }
                }
                else
                    goto end;
            }
            else
                goto succ;
        }
    }
    else /* JMS */
    {
        if (ui_len < 2)
            return APM_L7_IS_NO;
        memcpy(arr_len, p_payload, 2);
        arr_len[2] = '\0';
        p_u16_len = (uint16_t *)arr_len;
        ui_seg_len = be16toh(*p_u16_len);

        if (ui_seg_len != ui_len || ui_seg_len < 18)
            goto end;

        if (strncmp(p_payload+10, TLQ_TONG_JMS, 8) != 0)
            goto end;

        /* 方向不明确 */
        if (frct_get_direct_known(p_st_conn) != FR_DIRECT_KNOWN)
        {
            if (*(p_payload+5) == '\x01')
            {
                i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
                if (i_ret != FR_SUCC)
                {
                    frdbg("frcap_set_cs_srv failed\n");
                    return APM_L7_IS_NO;
                }
            }
        }
    }

succ:
    frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
    p_st_conn->flg_direct_known = FR_DIRECT_KNOWN;
    return APM_L7_IS_YES;

end:
    /* 长度为0的数据不进行识别协议查询 */
    if (ui_len == 0)
        return APM_L7_IS_NO;

    if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
            return APM_L7_IS_YES;
        }
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
            return APM_L7_IS_YES;
        }
    }
    else
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
            return APM_L7_IS_YES;
    }
    return APM_L7_IS_NO;
}

/*******************************************************************************
*  FUNC     :  TongLINK/Q的packet解析
*  ARGS     :  p_st_conn(入力链接信息)
            :  p_st_packet(入力packet信息)
            :  p_st_hash_report(保存Frreport_data)
*  RTN      :  参照module.h
*  NOTE     :
*******************************************************************************/
int tonglinkq_analysis(Conntrack *p_st_conn
                     , Apm_packet *p_st_packet
                     , Frhash_header *p_st_hash_report)
{
    L7session_tonglinkq_private *p_st_private = NULL;
    L7_session *p_st_session = NULL;
    int i_ret = 0;

    if (p_st_conn == NULL || p_st_packet == NULL
         || p_st_hash_report == NULL)
         return APM_L7_ANALYZE_FAIL;

    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    /*
    * 如果入力p_st_data_in是FIN包, 说明本次TongLINK/Q的connection结束,
    * 释放本次session信息. 如果入力p_st_data_in是SYN包,说明新的TongLINK/Q的
    * connection开始了, 释放上次可能残留的session信息
    */
    if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN
        || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        /* 销毁所有相关本次TongLINK/Q的connection的数据 */
        tonglinkq_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

     /* 本次链路的第一个有效packet包,创建链路 */
    if (p_st_session->p_session_private == NULL)
    {
        /* 初始化TongLINK/Q的私有数据 */
        i_ret = __tonglinkq_init_private(p_st_session);
        if (i_ret != FR_SUCC)
            return APM_L7_ANALYZE_FAIL;

        /* 设置session ID */
        fruuid(p_st_session->arr_session_id);
    }

    p_st_private = (L7session_tonglinkq_private *)p_st_session->p_session_private;

    if (p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
    {
        i_ret = __tonglinkq_getdata_req_analysis(p_st_private
                                               , p_st_conn
                                               , p_st_hash_report
                                               , p_st_packet
                                               , p_st_packet->p_payload
                                               , p_st_packet->ui_payload_len);
    }
    else
    {
        i_ret = __tonglinkq_getdata_resp_analysis(p_st_private
                                                , p_st_conn
                                                , p_st_hash_report
                                                , p_st_packet
                                                , p_st_packet->p_payload
                                                , p_st_packet->ui_payload_len);
    }
    return i_ret;
}
